package org.one.stone.soup.grfxML;

import java.net.URL;
import java.net.URLClassLoader;
import java.util.Hashtable;

import org.one.stone.soup.mjdb.data.field.DataLinker;
import org.one.stone.soup.mjdb.data.field.Field;
import org.one.stone.soup.mjdb.data.field.LockException;
import org.one.stone.soup.xml.XmlElement;
  /*
 * Copyright 2000-2001 Wet-Wired.com Ltd.,
 * Portsmouth England
 * All rights reserved.
 */

/**
	*
	* @author Nik Cross
*/
public  class DataActionPlugin extends DataAction implements ITag{
	public static String DEFAULT_ID="_ActionPlugin";

	private GrfxMLEngine engine;

	private String path = "";

	private DataString className = new DataString();
	private DataStore data;
	private DataPlugin plugin = null;
	private XmlElement pluginXml = null;

	private Hashtable classLoaderUrls = new Hashtable();
	private ClassLoader classLoader;

public DataActionPlugin(GrfxMLEngine engine,DataNode parent) {
	super(parent);

	this.engine = engine;
	classLoader = getClass().getClassLoader();

	data = new DataStore(engine);

	try{
		setId(DEFAULT_ID,this);

		looped.setValue( true,this );
		running.setValue( true,this );
	}
	catch(LockException le){} //Dummy catch
}
public void buildFromgrfxML(XmlElement xml)
{
//	ClassLoader classLoader = getClass().getClassLoader();

	String name = xml.getAttributeValueByName(Token.ID);
	if(name!=null)
	{
		try{
			setId(name,this);
		}
		catch(LockException le){} //Dummy catch
	}

	XmlElement element;

	for(int loop=0;loop<xml.getElementCount();loop++)
	{
		element = xml.getElementByIndex(loop);
		if(element == null)
			continue;

		String eleName = element.getName();

		if(eleName.equals(Token.CLASS_NAME))
		{
			className = new DataString();
			className.buildFromgrfxML(element);
			if(className.getValue().charAt(0)=='.')
			{
				try{
					className.setValue( NameHelper.PLUGIN_DEFAULT_PACKAGE_NAME+className.getValue(),this );
				}catch(LockException le){}
			}

//-------- Test plugin class -------------------------------------
			try{
				classLoader.loadClass(className.getValue());//Class.forName(className.getValue());
			}
			catch(ClassNotFoundException cnf)
			{
				GrfxMLException.warning( GrfxMLException.WARNING_BAD_PLUGIN_CODE ,new Object[]{className.getValue(),""+element.getStartLineNo()} );
			}
			catch(Exception e)
			{
				GrfxMLException.warning( GrfxMLException.UNKNOWN_CODE ,new Object[]{e} );
			}
		}
		else if(eleName.equals("jar"))
		{
			DataString jar = new DataString(TagModifier.STRING_TYPE_FILE);
			jar.buildFromgrfxML(element);

			if(engine.getAPI().userChoose(new String[]{"A plugin has requested the jar "+jar.getValue()})==false)
			{
				continue;
			}

			try{
				classLoaderUrls.put(jar.getValue(),new URL(jar.getValue()));
			}
			catch(Exception e){e.printStackTrace();}

			try{
				Object[] urlObj = classLoaderUrls.values().toArray();
				URL[] urls = new URL[urlObj.length];
				for(int loopA=0;loopA<urls.length;loopA++)
				{
					urls[loopA]=(URL)urlObj[loopA];
				}

				classLoader = new URLClassLoader(  urls,getClass().getClassLoader());
			}
			catch(Exception e){e.printStackTrace();}
		}
		else if(eleName.equals(Token.DATA))
		{
			data = new DataStore(engine);
			data.buildFromgrfxML(name,element,true);
		}
		else if(eleName.equals(Token.XML))
		{
			pluginXml = element;
		}
		else if(super.buildFromElement(element)==false && !NameHelper.isSystemName(element.getName()))
		{
			GrfxMLException.warning( GrfxMLException.WARNING_UNRECOGNISED_TAG_CODE ,new Object[]{eleName,Token.ACTION_PLUGIN,""+element.getStartLineNo()} );
		}
	}

	//buildPlugin();
}
/**
 *
 */
private void buildPlugin()
{
//------------------ Build plugin --------------------------
	try{
		if(plugin==null)
		{
			plugin = (DataPlugin)GrfxMLProcessor.buildInstance(classLoader,className.getValue(),engine);
			//plugin = (DataPlugin)Class.forName(className.getValue()).newInstance();
			plugin.setPath(path);
			plugin.parent = this;
			plugin.data = data;
			plugin.xml = pluginXml;
			if(!NameHelper.isSystemName( getId() ))
			{
				plugin.setId(getId(),this);
			}

			//APIInterface.getController().addPlugin(plugin);
		}
// Moved as multiple plugins were generated on API commit
//			APIInterface.getController().addPlugin(plugin);

// Replaced as multiple plugins are controlled by engine
// Needed for plugins in system node
			engine.addPlugin(plugin);

	}// catch no class def found error here
	catch(NoClassDefFoundError nc)
	{
		System.out.println( "ActionPlugin class "+className.getValue()+" not found." );
	}
	catch(Exception ce)
	{
		ce.printStackTrace();
	}//report error
//----------------------------------------------------------
}
public void copyFromgrfxML(XmlElement xml)
{
	XmlElement element;

	for(int loop=0;loop<xml.getElementCount();loop++)
	{
		element = xml.getElementByIndex(loop);
		if(element == null)
			continue;

		String eleName = element.getName();

		if(eleName.equals(Token.CLASS_NAME))
		{
			// Do not make copy of class
		}
		else if(eleName.equals(Token.DATA))
		{
			data.copyFromgrfxML(getId(),element,true);
		}
		else if(eleName.equals(Token.XML))
		{
			pluginXml = element;
		}
		else if(super.buildFromElement(element)==false)
		{
			GrfxMLException.warning( GrfxMLException.WARNING_UNRECOGNISED_TAG_CODE ,new Object[]{eleName,Token.ACTION_PLUGIN,""+element.getStartLineNo()} );
		}
	}
}
public DataString getClassName() {
	return className;
}
public DataAction getClone() {


	DataActionPlugin newActionPlugin = new DataActionPlugin(engine,parent);

	super.getClonedElements(newActionPlugin);

//	newActionPlugin.plugin = plugin.getClone();
	newActionPlugin.data = data.getClone();
	newActionPlugin.className = className;
	newActionPlugin.pluginXml = pluginXml;
	newActionPlugin.buildPlugin();

	return newActionPlugin;
}
public DataAction getClone(String path) {

	DataActionPlugin newActionPlugin = new DataActionPlugin(engine,parent);
	newActionPlugin.path=path+".";

	GrfxMLStoreProcessor.setCloneName( path,this,newActionPlugin );

	super.getClonedElements(path,newActionPlugin);

 	//newActionPlugin.plugin = plugin.getClone(path);
	newActionPlugin.data = data.getClone(path);
	newActionPlugin.className = className;
	newActionPlugin.pluginXml = pluginXml;
// 	newActionPlugin.buildPlugin();

	return newActionPlugin;
}
public DataStore getData() {
	return data;
}
public String getPath() {
	return path;
}
public DataPlugin getPlugin() {
	return plugin;
}
public XmlElement getPluginXml() {
	return pluginXml;
}
/**
 * process method comment.
 */
protected void process()
{
 //do nothing
}
public void register(DataLinker store) {

	super.register(store);

/*	if(data!=null)
	{
		try{
			store.add(data,this);
			data.register(store);
		}catch(LockException le){}
	}*/

	buildPlugin();

	if(plugin!=null)
	{
/*		try{
			store.add(plugin,this);
		}
		catch(LockException le)
		{}//Dummy catch
*/
		plugin.register(store);
	}

	try{
		store.add(className,this);
	}
	catch(LockException le)
	{}//Dummy catch

	try{
		store.add(data,this);
	}
	catch(LockException le)
	{}//Dummy catch
	data.register(store);

}
public void replace(Field oldObj, Field newObj) {

	replace(oldObj,newObj,false);

}
public void replace(Field oldObj, Field newObj,boolean recursive) {

	super.replace(oldObj,newObj);

	if(className==oldObj)
		className=(DataString)newObj;

	if(data==oldObj)
		data=(DataStore)newObj;

	if(recursive)
	{
		if(data!=null)
		{
			data.replace(oldObj,newObj,recursive);
		}

		/*if(plugin!=null)
		{
			plugin.replace(oldObj,newObj,recursive);
		}*/

		if(data!=null)
		{
			data.replace(oldObj,newObj,recursive);
		}
	}

}
public void resetChanged() {
	super.resetChanged();
	className.resetChanged();
	data.resetChanged();
	if (plugin != null) {
		plugin.resetChanged();
	}
}
protected void setClassName(DataString newClassName) {
	className = newClassName;
}
protected void setData(DataStore newData) {
	data = newData;
}
protected void setPath(String newPath) {
	path = newPath;
}
protected void setPlugin(DataPlugin newPlugin) {
	plugin = newPlugin;
}
public String togrfxML(String name) {
	String xml = "<" + name;

	if(!NameHelper.isSystemName(getId()))
	{
		xml += " id=\""+getId()+"\"";
	}

	xml += ">";
	xml += super.togrfxML(name);
	xml += className.togrfxML("className");
	xml += data.togrfxML("data");
	xml += "</" + name + ">\n";
	return xml;
}
public String toString()
{
	if(GrfxMLEngine.DEBUG)
		return(togrfxML( DEFAULT_ID.substring(1) ));

	String xml = "<"+DEFAULT_ID.substring(1)+"/> <!-- Plugin:"+plugin+" -->";

	return xml;
}
}
